package com.spark.searchservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.spark.searchapi.entity.PmsProduct;
import com.spark.searchservice.mapper.PmsProductMapper;
import com.spark.searchservice.repository.EsProductRepository;
import com.spark.searchservice.service.IEsProductService;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author fuqiang
 * @Description ES搜索商品
 * @Date 2021-03-05
 */
@Service
@AllArgsConstructor
public class EsProductServiceImpl implements IEsProductService {

    private static final Logger logger = LoggerFactory.getLogger(EsProductServiceImpl.class);

    private PmsProductMapper pmsProductMapper;
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    private EsProductRepository productRepository;

    @Override
    public List<PmsProduct> getAll() {
        return (List<PmsProduct>) productRepository.findAll();
    }

    @Override
    public Page<PmsProduct> getSimplePmsProduct(String keyword, Integer pageNum, Integer pageSize) {
        PageRequest of = PageRequest.of(pageNum, pageSize);
        return productRepository.findByNameOrSubTitleOrKeywords(keyword,keyword,keyword,of);
    }

    @Override
    public int importAll() {
        List<PmsProduct> pmsProducts = pmsProductMapper.selectList(new QueryWrapper<>());
        productRepository.deleteAll();
        Iterable<PmsProduct> products = productRepository.saveAll(pmsProducts);
        Iterator<PmsProduct> iterator = products.iterator();
        int count = 0;
        while(iterator.hasNext()){
            count++;
            iterator.next();
        }
        return count;
    }

    @Override
    public Page<PmsProduct> search(String keyword, Long brandId, Long productCategoryId, Integer pageNum, Integer pageSize, Integer sort) {
        PageRequest of = PageRequest.of(pageNum, pageSize);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        // 分页
        nativeSearchQueryBuilder.withPageable(of);
        // 过滤
        if(null != brandId || null != productCategoryId){
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if(null != brandId){
                boolQueryBuilder.must(QueryBuilders.termQuery("brandId",brandId));
            }
            if(null != productCategoryId){
                boolQueryBuilder.must(QueryBuilders.termQuery("productCategoryId",productCategoryId));
            }
            nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        }

        //搜索
        if (StringUtils.isEmpty(keyword)) {
            nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
        } else {
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("name", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(10)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("subTitle", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(5)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("keywords", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
        }
        //排序
        if(sort==1){
            //按新品从新到旧
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
        }else if(sort==2){
            //按销量从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sale").order(SortOrder.DESC));
        }else if(sort==3){
            //按价格从低到高
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
        }else if(sort==4){
            //按价格从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        }else{
            //按相关度
            nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        }
        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        logger.info("DSL:{}", searchQuery.getQuery().toString());
        SearchHits<PmsProduct> searchHits = elasticsearchRestTemplate.search(searchQuery, PmsProduct.class);
        if(searchHits.getTotalHits()<=0){
            return new PageImpl<>(null,of,0);
        }
        List<PmsProduct> searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return new PageImpl<>(searchProductList,of,searchHits.getTotalHits());
    }
}
